﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MethodWorx.CMS.Administration;
using MethodWorx.CMS.Content;
using System.Web.Mvc;
using MethodWorx.CMS.TemplateLanguage;
using System.Reflection;
using MethodWorx.CMS.Plugins.AssetManagement;
using MethodWorx.CMS.Providers;
using MethodWorx.CMS.Plugins.ContentTree;
using MethodWorx.CMS.Workflow;

namespace MethodWorx.CMS.Plugins
{
    public class PluginFactory
    {
        private ApplicationSettings applicationSettings;
        private ApplicationType applicationType;
        private IPluginRepository plugins;

        public PluginFactory(IApplicationSettingsRepository settings, IPluginRepository plugins)
        {
            this.applicationSettings = settings.FindSettings();
            if (this.applicationSettings != null)
                this.applicationType = ApplicationTypeFactory.Instance.GetApplicationTypes().FirstOrDefault(at => at.ApplicationTypeId == this.applicationSettings.ApplicationTypeId);

            this.plugins = plugins;
        }

        public IEnumerable<IWorkflowComponent> GetWorkflowComponents()
        {
            foreach (var p in this.plugins.All().OfType<SafePlugin>())
            {
                if (p.Is<IWorkflowPlugin>())
                {
                    foreach (var component in p.Invoke<IWorkflowPlugin, IEnumerable<IWorkflowComponent>>(c => c.GetWorkflowComponents()))
                    {
                        yield return component;
                    }
                }
            }
        }

        public IEnumerable<SafePlugin> GetRequestPlugins()
        {
            return this.plugins.All().OfType<SafePlugin>().Where(sp => sp.IsSafe && sp.Is<IRequestPlugin>());
        }

        public IEnumerable<SafePlugin> GetContentTreePlugins()
        {
            return this.plugins.All().OfType<SafePlugin>().Where(sp => sp.IsSafe && sp.Is<IContentTreePlugin>());
        }

        public IdeExtension GetIdeExtension(Guid id)
        {
            IdeExtension extension = null;

            if (this.applicationType != null && this.applicationType is IIdePlugin)
                extension = ((IIdePlugin)this.applicationType).GetIdeExtensions().FirstOrDefault(ide => ide.Id == id);

            if (extension == null)
            {
                foreach (SafePlugin plugin in this.plugins.All().OfType<SafePlugin>().Where(s => s.IsSafe == true && s.Is<IIdePlugin>()))
                {
                    extension = plugin.Invoke<IIdePlugin, IEnumerable<IdeExtension>>(e => e.GetIdeExtensions()).FirstOrDefault(ide => ide.Id == id);
                    if (extension != null)
                    {
                        //  set the plugin for the rest of the execution lifetime
                        extension.Plugin = plugin;
                        break;
                    }
                }
            }

            return extension;

        }

        public IEnumerable<IdeExtension> GetIdeExtensionsForPageTemplate(PageTemplate pageTemplate)
        {
            List<IdeExtension> extensions = new List<IdeExtension>();

            if (this.applicationType != null && this.applicationType is IIdePlugin)
                extensions.AddRange(((IIdePlugin)this.applicationType).GetIdeExtensionsForPageTemplate(pageTemplate));


            foreach (SafePlugin plugin in this.plugins.All().OfType<SafePlugin>().Where(s => s.IsSafe == true && s.Is<IIdePlugin>()))
            {
                extensions.AddRange(plugin.Invoke<IIdePlugin, IEnumerable<IdeExtension>>(t => t.GetIdeExtensionsForPageTemplate(pageTemplate)));
            }

            return extensions;
        }

        public IEnumerable<IdeExtension> GetIdeExtensionsForPage(Page page)
        {
            List<IdeExtension> extensions = new List<IdeExtension>();

            if (this.applicationType != null && this.applicationType is IIdePlugin)
                extensions.AddRange(((IIdePlugin)this.applicationType).GetIdeExtensionsForPage(page));


            foreach (SafePlugin plugin in this.plugins.All().OfType<SafePlugin>().Where(s => s.IsSafe == true && s.Is<IIdePlugin>()))
            {
                extensions.AddRange(plugin.Invoke<IIdePlugin, IEnumerable<IdeExtension>>(t => t.GetIdeExtensionsForPage(page)));
            }

            return extensions;
        }

        public IEnumerable<IParser> GetTmlExtensions()
        {
            List<IParser> extensions = new List<IParser>();

            if (this.applicationType != null && this.applicationType is ITmlPlugin)
                extensions.AddRange(((ITmlPlugin)this.applicationType).GetTmlExtensions());

            foreach (SafePlugin plugin in this.plugins.All().OfType<SafePlugin>().Where(s => s.IsSafe == true && s.Is<ITmlPlugin>()))
            {
                extensions.AddRange(plugin.Invoke<ITmlPlugin, IEnumerable<IParser>>(t => t.GetTmlExtensions()));
            }

            return extensions;
        }

        public IEnumerable<VirtualUrl> GetVirtualUrls(string filter, string contextType, string contextId)
        {
            List<VirtualUrl> virtualUrls = new List<VirtualUrl>();

            if (this.applicationType != null && this.applicationType is IRequestPlugin)
                virtualUrls.AddRange(((IRequestPlugin)this.applicationType).GetVirtualUrls(filter, contextType, contextId));

            foreach (SafePlugin plugin in this.plugins.All().OfType<SafePlugin>().Where(s => s.IsSafe == true && s.Is<IRequestPlugin>()))
            {

                var items = plugin.Invoke<IRequestPlugin, IEnumerable<VirtualUrl>>(
                            p => p.GetVirtualUrls(filter, contextType, contextId));
                if (items != null)
                {
                    virtualUrls.AddRange(items);
                }
            }

            return virtualUrls;
        }

      
    }
}
